﻿using System;
using System.Text;
using System.Collections.Generic;
using System.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Goldlight.Mvvm.Base.Infrastructure;
using System.ComponentModel;

namespace Goldlight.Mvvm.Base.Test
{
    /// <summary>
    /// Summary description for UnitTest1
    /// </summary>
    [TestClass]
    public class EditableObjectTest
    {
        #region Boilerplate
        public EditableObjectTest()
        {
            //
            // TODO: Add constructor logic here
            //
        }

        private TestContext testContextInstance;

        /// <summary>
        ///Gets or sets the test context which provides
        ///information about and functionality for the current test run.
        ///</summary>
        public TestContext TestContext
        {
            get
            {
                return testContextInstance;
            }
            set
            {
                testContextInstance = value;
            }
        }

        #region Additional test attributes
        //
        // You can use the following additional attributes as you write your tests:
        //
        // Use ClassInitialize to run code before running the first test in the class
        // [ClassInitialize()]
        // public static void MyClassInitialize(TestContext testContext) { }
        //
        // Use ClassCleanup to run code after all tests in a class have run
        // [ClassCleanup()]
        // public static void MyClassCleanup() { }
        //
        // Use TestInitialize to run code before running each test 
        // [TestInitialize()]
        // public void MyTestInitialize() { }
        //
        // Use TestCleanup to run code after each test has run
        // [TestCleanup()]
        // public void MyTestCleanup() { }
        //
        #endregion
        #endregion

        /// <summary>
        /// Ensure that CancelEdit rolls back any changes.
        /// </summary>
        [TestMethod]
        public void TestCancelEdit()
        {
            MyEditableObject obj = new MyEditableObject { Id = 1, LocalItem = "Item" };
            obj.BeginEdit();
            obj.LocalItem = "My item";
            obj.CancelEdit();
            Assert.AreEqual(obj.LocalItem, "Item");
        }

        /// <summary>
        /// Ensure that EndEdit saves the item.
        /// </summary>
        [TestMethod]
        public void TestEndEdit()
        {
            MyEditableObject obj = new MyEditableObject { Id = 1, LocalItem = "Item" };
            obj.BeginEdit();
            obj.LocalItem = "My item";
            obj.EndEdit();
            Assert.AreEqual(obj.LocalItem, "My item");
        }

        /// <summary>
        /// Ensure that EndEdit saves the item.
        /// </summary>
        [TestMethod]
        public void TestChanges()
        {
            MyEditableObject obj = new MyEditableObject { Id = 1, LocalItem = "Item" };
            obj.Id = 2;
            Assert.AreEqual(obj.Id, 2);
        }

        [TestMethod]
        public void TestValidation()
        {
            using (MyEditableObject obj = new MyEditableObject() { Id = -1, LocalItem = "" })
            {
                obj.BeginEdit();
                obj.Id = 0;
                obj.CancelEdit();
                string val = obj["Id"];
                Assert.IsFalse(string.IsNullOrEmpty(val));
            }
            //Assert.AreEqual(obj.Id, 2);
        }

        [TestMethod]
        public void TestValidationRemoval()
        {
            using (MyEditableObject obj = new MyEditableObject() { Id = -1, LocalItem = "" })
            {
                obj.BeginEdit();
                obj.Id = 0;
                obj.CancelEdit();
                Validation<MyEditableObject>.RemoveRules(obj, "Id");
                string val = obj["Id"];
                Assert.IsTrue(string.IsNullOrEmpty(val));
            }
        }

        /// <summary>
        /// Ensure that CancelEdit rolls back any changes.
        /// </summary>

        public class MyEditableObject : EditableViewModelBase, IDataErrorInfo, IDisposable
        {
            public MyEditableObject() : base()
            {

            }

            protected override void OnInitialize()
            {
                Validation<MyEditableObject>.AddValidation(this, "Id", r => r.Id > 0, "The ID must be greater than zero");
                Validation<MyEditableObject>.AddValidation(this, "ItemName", r => !string.IsNullOrEmpty(_item), "The name cannot be null or empty.");
                base.OnInitialize();
            }

            private string _item;
            private int _id;
            /// <summary>
            /// Get or set the id.
            /// </summary>
            public int Id
            {
                get { return _id; }
                set
                {
                    if (_id != value)
                    {
                        _id = value;
                        OnChanged(() => Id);
                    }
                }
            }
            /// <summary>
            /// Get or set the item...
            /// </summary>
            public string LocalItem
            {
                get { return _item; }
                set
                {
                    if (_item != value)
                    {
                        _item = value;
                        OnChanged(() => LocalItem);
                    }
                }
            }

            public string Error
            {
                get { return null; }
            }

            public string this[string columnName]
            {
                get { return Validation<MyEditableObject>.Validate(this, columnName); }
            }

            #region IDisposable Members

            public void Dispose()
            {
                throw new NotImplementedException();
            }

            #endregion
        }
    }
}
